/*--------------------------------------------------------------------------------------------------
Yatak Operation System Project Copyright 2012
Author : Ilya Churaev
Started : 20 Apr 2012		Updated : 29 Jun 2012
File Name : isr.c		Purpose : Hight level program for service of interruptions.
--------------------------------------------------------------------------------------------------*/
#include <yatak/yatak.h>
#include <yatak/port.h>
#include <yatak/isr.h>
#include <screen.h>

isr_t interrupt_handlers[256];

const char * exception_messages[] = 
{
	"#DE: Divide error",
	"#DB: Reserved",
	"###: Non Maskable Interrupt",
	"#BP: Breakpoint",
	"#OF: Overflow",
	"#BR: BOUND Range Exceeded",
	"#UD: Invalid Opcode",
	"#NM: No Math Coprocessor",
	"#DF: Double Fault",
	"###: Coprocessor Segment Overrun (reserved)",
	"#TS: Invalid TSS",
	"#NP: Segment Not Present",
	"#SS: Stack Segment Fault",
	"#GP: General Protection Fault",
	"#PF: Page Fault",
	"###: Reserved",
	"#MF: x87 FPU Error",
	"#AC: Alignment Check",
	"#MC: Machine Check",
	"#XM: SIMD Floating-Point Exception",
	"###: Reserved",
	"###: Reserved",
	"###: Reserved",
	"###: Reserved",
	"###: Reserved",
	"###: Reserved",
	"###: Reserved",
	"###: Reserved",
	"###: Reserved",
	"###: Reserved",
	"###: Reserved",
	"###: Reserved"
};

void register_interrupt_handler(uint8 n, isr_t handler)
{
	interrupt_handlers[n] = handler;
}

// This gets called from our ASM interrupt handler stub.
void isr_handler(registers_t regs)
{
	// This line is important. When the processor extends the 8-bit interrupt number
	// to a 32bit value, it sign-extends, not zero extends. So if the most significant
	// bit (0x80) is set, regs.int_no will be very large (about 0xffffff80).
	uint8 int_no = regs.int_no & 0xFF;
	if (interrupt_handlers[int_no] != 0)
	{
		isr_t handler = interrupt_handlers[int_no];
		handler(&regs);
	}
	else
	{
		cli ();
		kprintf("\nISR# 0x%x : %s\n", regs.int_no,exception_messages[regs.int_no]);
		kprintf("EAX = 0x%016x EBX = 0x%016x\nECX = 0x%016x EDX = 0x%016x\n", regs.eax, regs.ebx, regs.ecx, regs.edx);
		kprintf("ESI = 0x%016x EDI = 0x%016x\nCS  = 0x%016x EIP = 0x%016x\n", regs.esi, regs.edi, regs.cs, regs.eip);
		kprintf("SS  = 0x%016x ESP = 0x%016x\n", regs.ss, regs.esp);
		for(;;);
	}
}

// This gets called from our ASM interrupt handler stub.
void irq_handler(registers_t regs)
{
	// Send an EOI (end of interrupt) signal to the PICs.
	// If this interrupt involved the slave.
	if (regs.int_no >= 40)
	{
		// Send reset signal to slave.
		outportb(0xA0, 0x20);
	}
	// Send reset signal to master. (As well as slave, if necessary).
	outportb(0x20, 0x20);

	if (interrupt_handlers[regs.int_no] != 0)
	{
		isr_t handler = interrupt_handlers[regs.int_no];
		handler(&regs);
	}
}
